package gbench.test.mock;

import org.junit.Test;

import static java.text.MessageFormat.format;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 
 * @author xuqinghua
 *
 */
public class MyJiraClient {

	/**
	 * 发送 post请求访问本地应用并根据传递参数不同返回不同结果
	 * 
	 * @param api api 接口
	 * @return json 结构的文本
	 */
	public static String httpGet(final String api) {
		// 创建默认的httpClient实例.
		CloseableHttpClient httpclient = HttpClients.createDefault();

		// 创建httpget
		HttpGet httpget = new HttpGet(api);
		httpget.setHeader("Authorization", AUTHORIZATION);
		httpget.setHeader("Content-Type", CONTENT_TYPE_APL_JSON);
		String result = null;
		try {
			println("executing request " + httpget.getURI());
			CloseableHttpResponse response = httpclient.execute(httpget);
			try {
				HttpEntity entity = response.getEntity();
				if (entity != null) {
					println("--------------------------------------");
					result = EntityUtils.toString(entity, "UTF-8");
					println("Response content: " + result);
					println("--------------------------------------");
				}
			} finally {
				response.close();
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			// 关闭连接,释放资源
			try {
				httpclient.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		return result;
	}

	/**
	 * 创建文本
	 * 
	 * @param url      请求api地址
	 * @param params   请求正文的参数
	 * @param encoding 返回结果的解码方式
	 * @return json 结构的文本
	 */
	public static String httpPost(final String url, final Map<String, Object> params, final String encoding) {
		CloseableHttpClient httpClient = null;
		HttpPost httpPost = null;
		String result = null;
		try {
			httpClient = HttpClients.createDefault();
			httpPost = new HttpPost(url);
			httpPost.setHeader("Authorization", AUTHORIZATION);
			httpPost.setHeader("Content-Type", CONTENT_TYPE_APL_JSON);
			final var objM = new ObjectMapper();
			final String postBody = objM
					// .writerWithDefaultPrettyPrinter()
					.writeValueAsString(params);
			println(postBody);
			StringEntity entity = new StringEntity(postBody, "UTF-8");
			entity.setContentType("application/json;charset=UTF-8");
			httpPost.setEntity(entity);
			HttpResponse response = httpClient.execute(httpPost);
			if (response != null) {
				HttpEntity resEntity = response.getEntity();
				if (resEntity != null) {
					result = EntityUtils.toString(resEntity, encoding);
				}
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return result;
	}

	/**
	 * 修改 文本字段
	 * 
	 * @param url      请求api地址
	 * @param params   请求正文的参数
	 * @param encoding 返回结果的解码方式
	 * @return json 结构的文本
	 */
	public static String httpPut(final String url, final Map<String, Object> params, final String encoding) {
		CloseableHttpClient httpClient = null;
		HttpPut httpPutt = null;
		String result = null;
		try {
			httpClient = HttpClients.createDefault();
			httpPutt = new HttpPut(url);
			httpPutt.setHeader("Authorization", AUTHORIZATION);
			httpPutt.setHeader("Content-Type", CONTENT_TYPE_APL_JSON);
			final var objM = new ObjectMapper();
			final String postBody = objM
					// .writerWithDefaultPrettyPrinter()
					.writeValueAsString(params);
			println(postBody);
			StringEntity entity = new StringEntity(postBody, "UTF-8");
			entity.setContentType("application/json;charset=UTF-8");
			httpPutt.setEntity(entity);
			HttpResponse response = httpClient.execute(httpPutt);
			if (response != null) {
				HttpEntity resEntity = response.getEntity(); // 结果返回为null
				if (resEntity != null) {
					result = EntityUtils.toString(resEntity, encoding);
					println("httpPut", result);
				} else { // HTTP状态204 (No Content)表示服务器已成功完成请求,并且在响应有效负载正文中没有要发送的内容。
					println("httpPut status code", response.getStatusLine().getStatusCode());
				}
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return result;
	}

	/**
	 * 为 问题 添加 附件
	 * 
	 * @param user         用户名
	 * @param password     密码
	 * @param issueKey     问题的key
	 * @param fileToUpload 附件文件
	 * @return 是否添加成功
	 */
	public static boolean addAttachmentToIssue(final String issueKey, final File fileToUpload) {

		final CloseableHttpClient httpclient = HttpClients.createDefault();
		final HttpPost httppost = new HttpPost(JIRA_API_URL_PREFIX + "issue/" + issueKey + "/attachments");
		httppost.setHeader("X-Atlassian-Token", "nocheck");
		httppost.setHeader("Authorization", AUTHORIZATION);

		final MultipartEntityBuilder builder = MultipartEntityBuilder.create();
		builder.setMode(HttpMultipartMode.RFC6532); // 设置多媒体模式
		builder.addBinaryBody("file", fileToUpload); // 附件
		final var entity = builder.build();
		httppost.setEntity(entity);

		HttpResponse response = null;
		try {
			response = httpclient.execute(httppost);
		} catch (ClientProtocolException e) {
			return false;
		} catch (IOException e) {
			return false;
		}

		HttpEntity resEntity = response.getEntity();
		String encoding = "utf-8";
		try {
			String result = EntityUtils.toString(resEntity, encoding);
			println(result);
		} catch (ParseException | IOException e) {
			e.printStackTrace();
		}

		if (response.getStatusLine().getStatusCode() == 200)
			return true;
		else
			return false;
	}

	/**
	 * 为 问题 添加 附件
	 * 
	 * @param user           用户名
	 * @param password       密码
	 * @param issueKey       问题的key
	 * @param attachmentpath 附件的文件路径
	 * @return 是否添加成功
	 */
	public static boolean addAttachmentToIssue(final String issueKey, final String attachmentpath) {

		final File fileToUpload = new File(attachmentpath);

		return addAttachmentToIssue(issueKey, fileToUpload);

	}

	/**
	 * 简写的输出函数
	 * 
	 * @param objects 输出文本序列，序列之间采用 "\t" 进行风格
	 */
	public static void println(final Object... objects) {
		System.out.println(Arrays.asList(objects).stream().map(Object::toString).collect(Collectors.joining("\t")));
	}

	/**
	 * 使用Base64 加密 用户名何密码
	 * 
	 * @param user     用户名
	 * @param password 密码
	 * @return user:password Base64 加密后的 密文
	 */
	public static String AUTH_ENCODE(String user, String password) {
		final String auth = new String(Base64.encodeBase64((user + ":" + password).getBytes()));
		return auth;
	}

	/**
	 * 把 一个 键名,键值 序列, 转换成 一个 key-value 键值对儿 文档
	 * 
	 * @param objects 键名,键值 序列 比如 name,"zhangsan","sex","男",....
	 * @return key-value 键值对儿 的map 结构
	 */
	public static Map<String, Object> REC(Object... objects) {
		final Map<String, Object> json = new HashMap<String, Object>();
		for (int i = 0; i < objects.length - 1; i += 2) {
			final String key = objects[i] + "";
			final Object value = objects[i + 1];
			json.put(key, value);
		}
		return json;
	}

	/**
	 * 把一段json文本 转换成 Map 结构
	 * 
	 * @param json json文本
	 * @return Map 结构
	 */
	@SuppressWarnings("unchecked")
	public static Map<String, Object> parseJson(final String json) {
		final var objM = new ObjectMapper();
		Map<String, Object> map = null;

		try {
			map = (Map<String, Object>) objM.readValue(json, Map.class);
		} catch (JsonProcessingException e) {
			e.printStackTrace();
		}

		return map;
	}

	/**
	 * 接口演示代码
	 */
	@SuppressWarnings("unchecked")
	@Test
	public void foo() {
		MyJiraClient.httpGet("http://localhost:8080/rest/api/2/issue/IT-3"); // 查看问题issue
		MyJiraClient.httpGet("http://localhost:8080/rest/api/2/project"); // 查看項目列表
		final var issuetypes_doc = MyJiraClient
				.httpGet("http://localhost:8080/rest/api/2/issue/createmeta/IT/issuetypes"); // 查看问题类型
		final var issuetypes_json = parseJson(issuetypes_doc); // 解析成Map结构
		final var issuetypes = (List<Map<String, Object>>) issuetypes_json.get("values");
		issuetypes.forEach(issuetype_meta -> { // issuetype_meta
			final var id = issuetype_meta.get("id");
			final var name = issuetype_meta.get("name");
			final var description = issuetype_meta.get("description");
			final var subtask = issuetype_meta.get("subtask");
			final var self = issuetype_meta.get("self");
			println(id, name, description, subtask, self);
		});

		final var flds = MyJiraClient.httpGet("http://localhost:8080/rest/api/2/issue/createmeta/IT/issuetypes/10001"); // 查看項目字段
		final var mapflds = parseJson(flds);
		final var fields = (List<Map<String, Object>>) mapflds.get("values");
		println("问题的 编辑:字段列表");
		fields.forEach(fld_meta -> { // fld_meta
			final var required = fld_meta.get("required");
			final var name = fld_meta.get("name");
			final var fieldId = fld_meta.get("fieldId");
			final var schema = fld_meta.get("schema");
			println(fieldId, name, required, schema);
		});

		final String issueName = format("需求故事{0}", LocalDateTime.now());
		final var summary = format("issue summary {0}", LocalDateTime.now());
		final var data = REC("fields", REC( //
				"project", REC("key", "IT"), //
				"issuetype", REC("id", 10001), //
				"summary", format("issue summary {0}", LocalDateTime.now()), //
				"description", issueName));
		println(data);
		final var res = MyJiraClient.httpPost("http://localhost:8080/rest/api/2/issue", data, "utf-8");
		final var json = parseJson(res);
		if (json != null) {
			final var issueKey = json.get("key") + ""; // 提取问题 issuekey
			MyJiraClient.addAttachmentToIssue(issueKey, "E:\\slicee\\ws\\项目\\核酸检测费用\\核酸检测费用.rar");
			final var api = format("http://localhost:8080/rest/api/2/issue/{0}", issueKey);
			// 修改字段
			// https://developer.atlassian.com/server/jira/platform/jira-rest-api-examples/#editing-an-issue-examples
			MyJiraClient.httpPut(api, REC("fields",
					REC("summary", summary + "_" + Math.random(), "description", issueName + "_" + Math.random())),
					"utf-8");
		} else {
			println("非json 结构");
			println(res);
		}
	}

	public static final String JIRA_API_URL_PREFIX = "http://localhost:8080/rest/api/2/";
	public static final String AUTHORIZATION = format("Basic {0}", AUTH_ENCODE("gbench", "pi31415926"));
	public static final String CONTENT_TYPE_APL_JSON = "application/json";

}
